﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UObject = UnityEngine.Object;

public class ResourceManager : MonoBehaviour
{
    /// <summary>
    /// AB包信息
    /// </summary>
    internal struct ABundleInfo
    {
        public string AssetsName; //资源名称
        public string BundleName; //AB包名称
        public List<string> Dependences; //依赖项
        public ABundleInfo(string g,string gh,List<string> a)
        {
            AssetsName = g;
            BundleName = gh;
            Dependences = a;
        }
    }

    internal class BundleData
    {
        public AssetBundle Bundle;
        public int Count;
        public BundleData(AssetBundle ab)
        {
            Bundle = ab;
            Count = 1;
        }
    }             


    //存储ABundleInfo信息的集合
    private Dictionary<string, ABundleInfo> m_BundleInfos = new Dictionary<string, ABundleInfo>();
    //存储ABundleData信息的集合
    private Dictionary<string, BundleData> m_BundleData = new Dictionary<string, BundleData>();

    /// <summary>
    /// 解析版本文件列表
    /// </summary>
    public void ParseVersionFile()
    {

        //版本文件的路径 + 文件名
        string url = Path.Combine(PathUtil.ABundleResourcePath, AppConst.FileListName);
        string[] data = File.ReadAllLines(url); //读取文件列表

        //解析文件信息
        for (int i = 0; i < data.Length; i++)
        {
            ABundleInfo bundleInfo = new ABundleInfo();
            string[] info = data[i].Split('|'); //分隔符存储到数组
            bundleInfo.AssetsName = info[0]; //存储第一个
            bundleInfo.BundleName = info[1]; //存储第2个
            //list特性：本质是数组，但可动态扩容
            bundleInfo.Dependences = new List<string>(info.Length - 2); //依赖项实例化
            for (int j = 2; j < info.Length; j++)
            {
                bundleInfo.Dependences.Add(info[j]); //添加依赖项
            }
            m_BundleInfos.Add(bundleInfo.AssetsName, bundleInfo);

            //专门获取 Lua文件
            if (info[0].IndexOf("Lua", StringComparison.CurrentCulture) > 0)
            {
                Manager.LuaManager.luaFileNames.Add(info[0]);
                Debug.Log(info[0].ToString());
            }
        }
    }

    #region Load_Asset

    /// <summary>
    /// 加载UI资源
    /// </summary>
    /// <param name="assetName">资源名称</param>
    /// <param name="action">回调方法</param>
    public void LoadUI(string assetName, Action<UObject> action = null)
    {
        LoadAsset(PathUtil.GetUIPath(assetName),action);
    }

    public void LoadMusic(string assetName, Action<UnityEngine.Object> action = null)
    {
        LoadAsset(PathUtil.GetMusicPath(assetName), action);
    }

    public void LoadSound(string assetName, Action<UnityEngine.Object> action = null)
    {
        LoadAsset(PathUtil.GetSoundPath(assetName), action);
    }

    public void LoadEffect(string assetName, Action<UnityEngine.Object> action = null)
    {
        LoadAsset(PathUtil.GetEffectPath(assetName), action);
    }

    public void LoadScene(string assetName, Action<UnityEngine.Object> action = null)
    {
        LoadAsset(PathUtil.GetScenePath(assetName), action);
    }

    public void LoadLua(string assetName, Action<UnityEngine.Object> action = null)
    {
        LoadAsset(assetName, action);
    }

    public void LoadPrefab(string assetName, Action<UnityEngine.Object> action = null)
    {
        LoadAsset(assetName, action);
    }
    #endregion

#if UNITY_EDITOR
    /// <summary>
    /// 编辑器环境加载资源
    /// </summary>
    /// <param name="assetPathName"></param>
    /// <param name="action"></param>
    private void EditorLoadAsset(string assetPathName, Action<UObject> action = null)
    {
        Debug.Log("this is EditorLoadAsset");
        UObject obj = UnityEditor.AssetDatabase.LoadAssetAtPath(assetPathName, typeof(UObject));
        if (obj == null)
            Debug.LogError("assets name is not exist:" + assetPathName);
        action?.Invoke(obj);
    }
#endif

    /// <summary>
    /// 加载资源
    /// 对外提供的接口
    /// </summary>
    /// <param name="assetPathName">资源路径名称</param>
    /// <param name="action"></param>
    public void LoadAsset(string assetPathName, Action<UObject> action = null)
    {
#if UNITY_EDITOR
        if (AppConst.gameMode == GameMode.EditorMode)
            EditorLoadAsset(assetPathName, action);
        else
#endif
            StartCoroutine(LoadBundleAsync(assetPathName, action));
    }

    /// <summary>
    /// 异步加载资源AB包
    /// </summary>
    /// <param name="_assetPath">资源路径名称</param>
    /// <param name="action">完成回调</param>
    /// <returns></returns>
    private IEnumerator LoadBundleAsync(string _assetPath, Action<UObject> action = null)
    {
        string bundleName = m_BundleInfos[_assetPath].BundleName;
        string bundlePath = Path.Combine(PathUtil.ABundleResourcePath, bundleName); //Ab包路径

        List<string> dependences = m_BundleInfos[_assetPath].Dependences;

        //解决BUG：加载Bundle资源已加载的重复使用
        BundleData bundle = GetBundle(bundleName);
        //if (bundle == null)
        //{
        //    UObject obj = Manager.Pool.Spawn("AssetBundle", bundleName);
        //    if (obj != null)
        //    {
        //        AssetBundle ab = obj as AssetBundle;
        //        bundle = new BundleData(ab);
        //    }
        //    else
        //    {
        //        AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync(bundlePath);
        //        yield return request;
        //        bundle = new BundleData(request.assetBundle);
        //    }
        //    m_AssetBundles.Add(bundleName, bundle);
        //}

        //如果存在依赖项
        if (dependences != null && dependences.Count > 0)
        {
            for (int i = 0; i < dependences.Count; i++)
            {
                yield return LoadBundleAsync(dependences[i]); //异步读取AB包依赖项
            }
        }

        AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync(bundlePath);

        if (_assetPath.EndsWith(".unity", StringComparison.CurrentCulture))
        {
            action?.Invoke(null);
            yield break;
        }

        if (action == null)
        {
            yield break;
        }

        ////异步读取AB包请求
        AssetBundleRequest bundleRequest = request.assetBundle.LoadAssetAsync(_assetPath);
        yield return bundleRequest;


        Debug.Log("this is LoadBundleAsync");
        //action?.Invoke(bundleRequest?.asset); //语法糖，和下面是一样的
        if (action != null && bundleRequest != null)
        {
            action.Invoke(bundleRequest.asset);
        }
    }

    private BundleData GetBundle(string bundleName)
    {
        BundleData bundleData = null;
        if (m_BundleData.TryGetValue(bundleName,out bundleData))
        {
            bundleData.Count++;
            return bundleData;
        }
        return null;
    }
}
